package com.dy.design_pattern_study.flyweight_pattern.dome3;

import com.dy.design_pattern_study.flyweight_pattern.dome3.factory.WebSiteFactory;
import com.dy.design_pattern_study.flyweight_pattern.dome3.impl.UnsharedConcreteWebSite;

/**
 * @CreateBy zhangdingyi
 * @Date 2023-04-23
 * @Content 享元模式（Flyweight）
 * 运用共享技术有效地支持大量细粒度的对象
 * <p>
 * 简单的说：
 * 一个系统中如果有多处用到了相同的一个元素,那么我们应该只存储一份此元素,而让所有地方都引用这一个元素
 * 就是封装通用类方法，这里是以整个功能为基础，如果功能中使用到很多的对象，这里就可以进行一个封装使用
 */
public class client {
    /*
        尽管我们大部分时间都需要共享对象来降低内存的损耗，
        但个别时候也有可能不需要共享的，
        那么此时的 UnsharedConcreteWebSite 子类就有存在的必要了，
        它可以解决那些不需要共享对象的问题
     */

    /*
        享元模式的内部状态与外部状态

        享元模式可以避免大量非常相似类的开销。
        在程序设计中，有时需要生成大量细粒度的类实例来表示数据。
        如果能发现这些实例除了几个参数外基本上都是相同的，有时就能够受大幅度地减少需要实例化的类的数量。
        如果能把那些参数移到类实例的外面，在方法调用时将它们传递进来，就可以通过共享大幅度地减少单个实例的数目

        简单的说，
        内部状态就是 相同的步骤创建相同的实例
        外部状态就是 把内部状态需要使用到的参数提取到外部进行传入，这个就是外部状态
     */

    /*
        享元模式的应用
        其实字符串常量池也是享元模式的一种应用

        如果一个应用程序使用了大量的对象，而大量的这些对象造成了很大的存储开销时就应该考虑使用；
        还有就是对象的大多数状态可以外部状态，如果删除对象的外部状态，
        那么可以用相对较少的共享对象取代很多组对象，此时可以考虑使用享元模式。

        简单的说
            1.就是在功能上使用到很大量的对象，造成极大的系统开销时使用
            2.然后就是如果可以把这些大量开销的对象，外部状态进行提取，然后有一个通用的模板，
            这时候就可以把这些对象进行一个封装，尽可能的使用。（感觉跟封装工具类的方法是类似的）
     */

    /*
        享元模式的优缺点：
        优点：减少系统开销、通用对象复用
        缺点：
           就是会让程序变得更复杂
        使用享元模式需要维护一个记录了系统已有的所有享元的列表，而这本身需要耗费资源，另外享元模式使得系统更加复杂。
        为了使对象可以共享，需要将一些状态外部化，这使得程序的逻辑复杂化。
        因此，应当在有足够多的对象实例可供共享时才值得使用享元模式
     */

    public static void main(String[] args) {
        WebSiteFactory f = new WebSiteFactory();

        WebSite fx = f.getWebSiteCategory("产品展示");
        fx.use(new User("userA"));

        WebSite fy = f.getWebSiteCategory("产品展示");
        fy.use(new User("userB"));

        WebSite fz = f.getWebSiteCategory("产品展示");
        fz.use(new User("userC"));

        WebSite f1 = f.getWebSiteCategory("博客");
        f1.use(new User("userD"));

        WebSite f2 = f.getWebSiteCategory("博客");
        f2.use(new User("userE"));

        WebSite f3 = f.getWebSiteCategory("博客");
        f3.use(new User("userF"));

        WebSite uf = new UnsharedConcreteWebSite("私有AA博客");
        uf.use(new User("私有userF"));

        System.out.println("网站分类总个数：" + f.getWebSiteCount());
    }
}
